if(window) {
if(window.Sprite) {
    throw new Error('Sprite被占用');
} else {
/* --======================================-- */
/* --======================================-- */
window.Sprite = (function (){
    /**
     * 精灵类构造函数
     * @param {String} name 精灵的名字标识
     * @param {Painter} painter 绘制器对象实例
     * @param {Array(Behavior)} behaviors 行为实例数组
     */
    function Sprite (name, behaviors) {
        if(name !== undefined) this.name = name;
        // if(painterAction !== undefined) this.painter = new Sprite.Painter(painterAction);
        this.top = 0; //精灵绘制位置左上角点的 x 坐标
        this.left = 0; //精灵绘制位置左上角点的 y 坐标
        this.width = 10; //精灵绘制宽度
        this.height = 10; //精灵绘制高度
        this.vX = 0; //移动速率的 x 轴分量
        this.vY = 0; //移动速率的 y 轴分量
        this.visible = true; //是否绘制的boolean标识
        this.animating = false; //是否正在执行动画效果的boolean标识
        this.behaviors = behaviors || []; //行为数组
    }

    /**
     * 精灵类原型对象
     */
    Sprite.prototype = {
        /**
         * 绘制函数，主要目的是将绘制行为代理给绘制器进行（策略模式）
         */
        paint: function (ctx) {
            if(this.painter !== undefined) {
                if(this.visible) {
                    this.painter.paint(this, ctx);
                }
            } else {
                throw new Error('精灵调用paint方法时未注册绘制器');
            }
        },
    
        /**
         * 顺序执行行为，只调用执行函数，不实际操作绘制，而是交给行为对象（命令模式）
         */
        update: function (ctx, time) {
            if(this.behaviors.length !== 0) {
                for(var i = 0; i < this.behaviors.length; i += 1) {
                    this.behaviors[i].execute(this, ctx, time);
                }
            }
        },

        /**
         * 根据传入对象形式，初始化对应的绘制器
         */
        setPainter: function (param) {
            if(param.action) {
                for(var key in param) {
                    if (param.hasOwnProperty(key)) {
                        if(key === 'imgUrl') {
                            this.painter = new Sprite.ImagePainter(param.imgUrl, param.action); return;
                        } else if (key === 'spriteSheetUrl') {
                            this.painter = new Sprite.SpriteSheetPainter(param.spriteSheetUrl, param.cells, param.action); return;
                        } else {
                            this.painter = new Sprite.StrokeAndFillPainter(param.action); return;
                        }
                    }
                }
            } else {
                throw new Error('参数 action 必要');
            }
        },

        /**
         * 新增行为，接收一个行为对象作为参数
         */
        addBehavior: function (execute, param) {
            if(!execute || typeof execute !== 'function') throw new Error('参数 execute 必要且为函数');
            if(typeof param === 'object' && param.length) throw new Error('参数 param 应为对象字面量');
            var behavior = new Behavior(execute, param);
            this.behaviors.push(behavior);
        },

        /**
         * 删除行为，接收一个行为对象作为参数
         */
        removeBehavior: function (behavior) {
            for(var i = 0; i < this.behaviors.length; i += 1) {
                if(behavior === this.behaviors[i]) {
                    this.behaviors.splice(i, 1);
                }
            }   
        }
    }

    /**************************绘制器*************************** */
    /**
     * 描边填充绘制器构造函数
     * @param {Function} action 外部定义的回调绘制算法函数，接受当前精灵实例sprite 和 绘图环境对象ctx，作为参数。
     */
    Sprite.StrokeAndFillPainter = function (action) {
        if(typeof action !== 'function') throw new Error('active 必须且是函数类型');
        this.action = action;
    };
    Sprite.StrokeAndFillPainter.prototype = {
        /* 调用绘制函数执行 */
        paint: function (sprite, ctx) { this.action(sprite, ctx); }
    };

    /**
     * 图像绘制器构造函数
     * @param {String} imgUrl 要绘制的图片的url
     * @param {Function} action 外部定义的回调绘制算法函数，接收 精灵sprite、绘制环境ctx，作为参数
     */
    Sprite.ImagePainter = function (imgUrl, action) {
        if(imgUrl === '' || typeof imgUrl !== 'string') throw new Error('参数 imgUrl 必要且为字符串');
        if(typeof action !== 'function') throw new Error('active 必须且是函数类型');
        this.action = action;
        this.image = new Image();
        this.image.src = imgUrl;
    }
    Sprite.ImagePainter.prototype = {
        /* 调用绘制函数执行 */
        paint: function (sprite, ctx) {
            var timer, that = this;
            if (that.image.complete) {
                that.action(sprite, ctx);
            } else {
                timer = setInterval( function () {
                    if(that.image.complete) {
                        that.paint(sprite, ctx);
                        clearInterval(timer);
                    }
                }, 50);
            }
        }
    }

    /**
     * 精灵表绘制器构造函数
     * @param {Array} cells 维护精灵表图像单元格信息数组
     * @param {Function} action 外部定义的回调绘制算法函数，接收 精灵sprite、绘图环境ctx，作为参数
     */
    Sprite.SpriteSheetPainter = function (spriteSheetUrl, cells, action) {
        if(spriteSheetUrl === '' || typeof spriteSheetUrl !== 'string') throw new Error('参数 imgUrl 必要且为字符串');
        if(!cells.length) throw new Error('参数 cells 必要且为数组');
        if(typeof action !== 'function') throw new Error('active 必须且是函数类型');
        this.action = action;
        this.spriteSheet = new Image();
        this.spriteSheet.src = spriteSheetUrl;
        this.cells = cells || [];
        this.cellIndex = 0;
    }
    Sprite.SpriteSheetPainter.prototype = {
        advance: function () {
            if(this.cellIndex === this.cells.length - 1) {
                this.cellIndex = 0;
            } else {
                this.cellIndex++;
            }
        },
        paint: function (sprite, ctx) {
            var timer, that = this;
            if(that.spriteSheet.complete) {
                var cell = that.cells[that.cellIndex];
                that.action(sprite, ctx);
            } else {
                timer = setInterval( function () {
                    if(that.spriteSheet.complete) {
                        that.paint(sprite, ctx);
                        clearInterval(timer);
                    }
                }, 50);
            }
        }
    }

    
    /**************************行为类*************************** */
    /**
     * 行为类构造函数
     * @param {Function} execute 行为最终的执行函数
     * @param {Object} param 对象字面量，给出某个行为独有的辅助变量
     */
    var Behavior = function (execute, param) {
        if(!execute || typeof execute !== 'function') throw new Error('参数 execute 必要且为函数');
        this.action = execute;
        if(param && typeof param === 'object' && !param.length) {
            for(var key in param) {
                if(param.hasOwnProperty(key)) {
                    this[key] = param[key];
                }
            }
        }
    }
    Behavior.prototype = {
        execute: function (sprite, ctx, time) {
            this.action(sprite, this, ctx, time)
        }
    }

    
    /**************************精灵动画制作器*************************** */
    Sprite.SpriteAnimator = function (painters, callBack) {
        this.painters = painters || [];
        this.callBack = callBack;
        this.duration = 1000;
        this.startTime = 0;
        this.index = 0;
    }
    Sprite.SpriteAnimator.prototype = {
        end: function (sprite, originalPainter) {
            sprite.animating = false;
            if(this.callBack) this.callBack(sprite);
            else sprite.painter = originalPainter;
        },
        start: function (sprite, duration) {
            var endTime = +new Date() + duration,
                period = duration / this.painters.length,
                animator = this,
                originalPainter = sprite.painter,
                lastUpdate = 0,
                id;
            
            this.index = 0;
            sprite.animating = true;
            sprite.painter = this.painters[this.index];
            id = requestAnimationFrame( function spriteAnimatorAnimate(time) {
                if(time < endTime) {
                    if((time - lastUpdate) > period) {
                        sprite.painter = animator.painters[++animator.index];
                        lastUpdate = time;
                    }
                } else {
                    animator.end(sprite, originalPainter);
                    cancelAnimationFrame(id);
                }
            })
        }
    }


    return Sprite;
}());

/* --======================================-- */
/* --======================================-- */
}
} else {
    throw new Error('错误的环境');
}

/**
 * 记录一下Sprite类对外提供的接口和功能
 * 1.构造函数
 *      var sprite = new Sprite('name', drawSprite, behaviors);
 * 
 * 2.绘制函数 sprite.paint(ctx)
 */